module(..., package.seeall) -- 使得文件中的函数在何处都可调用
require "pins"              -- 用到了pin库，该库为luatask专用库，需要进行引用
require "sys"
require "uartTask"
require "audio"
require "math"
require "nvm"
require "send433RFSignal"
require "logGenerator"
require "earthquakeWaring"
nvm.init("config.lua", true)
DoLampTask = true
local ttsStr = "预警系统演练"
local toneDowns, toneBreak, doToneTask, lampDowns, lampBreak, signalDowns,
signalBreak, doSignalTask, countDownSDrill, quake_intensity,
equipment_clients, alarm433Bool, warnCancelTTSBroadcastCount, emergencyLightOpenBreak, doEmergencyLightOpen = 0, false,
    true, 0,
    false, 0,
    false,
    true, 0, 0,
    "", false,
    0, false, true
TTS = 1
local setGpio9Fnc = pins.setup(pio.P0_9, 1)   -- 静音设置（高电平静音）
local setGpio10Fnc = pins.setup(pio.P0_10, 0) -- 预警指示
local setGpio11Fnc = pins.setup(pio.P0_11, 0) -- Buzzer正常低电平，预警高电平
local setGpio17Fnc = pins.setup(pio.P0_17, 0) -- 地震预警测试音量控制音量25%，高电平为测试音量（音量小），低电平为正常音量（音量大）
local setGpio16Fnc = pins.setup(pio.P0_16, 0) -- 地震预警测试音量控制音量50%，高电平为测试音量（音量小），低电平为正常音量（音量大）
local setGpio1Fnc = pins.setup(pio.P0_1, 0)   -- 地震预警测试音量控制音量75%，高电平为测试音量（音量小），低电平为正常音量（音量大）
-- local setGpio12Fnc = pins.setup(pio.P0_12, 0) -- 报警灯
local setGpio2Fnc = pins.setup(pio.P0_2, 0)   -- 蓝色
local setGpio3Fnc = pins.setup(pio.P0_3, 0)   -- 红色
local setGpio13Fnc = pins.setup(pio.P0_13, 0) -- 绿色

-- 获取配置参数
local configIntensity, enable433, countDown, alertSound, alertLight,
magnitudeConfig, centerIntensityConfig, emergencyLamp, relay, luminance,
alertVolume, blueLimit, yellowLimit, orangeLimit, redLimit, afterSecond,
exerciseText, cancelCount, hz = tonumber(nvm.get("intensity")),
    nvm.get("enable433"),
    tonumber(nvm.get("countDown")),
    tonumber(nvm.get("alertSound")),
    tonumber(nvm.get("alertLight")),
    tonumber(nvm.get("magnitude")),
    tonumber(nvm.get("centerIntensity")),
    tonumber(nvm.get("emergencyLamp")),
    tonumber(nvm.get("relay")),
    tonumber(nvm.get("luminance")),
    tonumber(nvm.get("alertVolume")),
    tonumber(nvm.get("blueLimit")),
    tonumber(nvm.get("yellowLimit")),
    tonumber(nvm.get("orangeLimit")),
    tonumber(nvm.get("redLimit")),
    tonumber(nvm.get("afterSecond")),
    nvm.get("exerciseText"),
    tonumber(nvm.get("cancelCount")),
    nvm.get("hz")

-- 报警灯一秒闪烁次数
local function lampSlash1s(hzSet)
    local flashTime = 0
    if hzSet == "01" then
        flashTime = 1
    elseif hzSet == "02" then
        flashTime = 2
    elseif hzSet == "03" then
        flashTime = 3
    elseif hzSet == "04" then
        flashTime = 4
    elseif hzSet == "05" then
        flashTime = 5
    elseif hzSet == "06" then
        flashTime = 6
    elseif hzSet == "07" then
        flashTime = 7
    elseif hzSet == "08" then
        flashTime = 8
    elseif hzSet == "09" then
        flashTime = 9
    elseif hzSet == "10" then
        flashTime = 10
    end
    return flashTime
end
-- 烈度转换为阈值
local function intensity2Threshold(intensity2Th)
    local threhold = 0
    log.info("intensity2Th", intensity2Th, "blueLimit", blueLimit,
        "yellowLimit", yellowLimit, "redLimit", redLimit)
    if intensity2Th >= blueLimit and intensity2Th < yellowLimit then
        threhold = 1
    elseif intensity2Th >= yellowLimit and intensity2Th < orangeLimit then
        threhold = 2
    elseif intensity2Th >= orangeLimit and intensity2Th < redLimit then
        threhold = 3
    elseif intensity2Th >= redLimit then
        threhold = 4
    end
    return threhold
end
-- 应急照明灯打开任务
local function emergencyLightOpenTask()
    local emergencyLightOpenDowns = 0
    doEmergencyLightOpen = false
    log.info("应急照明灯打开！！")
    setGpio11Fnc(1)
    while emergencyLightOpenDowns >= 0 and emergencyLightOpenDowns <= 5400 do
        if emergencyLightOpenBreak then
            emergencyLightOpenBreak = false
            break
        end
        sys.wait(1000)
        if emergencyLightOpenBreak then
            emergencyLightOpenBreak = false
            break
        end
        emergencyLightOpenDowns = emergencyLightOpenDowns + 1
    end
    setGpio11Fnc(0)
    doEmergencyLightOpen = true
end
-- 报警灯操作任务
local function alarmLampOperationTask(countD)
    local countFlash = lampSlash1s(hz) -- 报警灯一秒闪烁次数
    local colorSelect = intensity2Threshold(quake_intensity)
    log.info("colorSelect:", colorSelect, "countFlash:", countFlash, "hz:", hz)
    DoLampTask = false
    lampDowns = countD
    while lampDowns >= 0 do
        log.info("lampBreak:", lampBreak)
        if lampBreak then
            lampDowns = 0
            lampBreak = false
            break
        end
        if lampDowns % 2 == 0 then
            for i = 1, countFlash, 1 do
                if lampBreak then break end
                if colorSelect == 1 then -- 蓝灯闪烁一秒
                    setGpio2Fnc(1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio2Fnc(0)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 2 then -- 黄灯闪烁一秒
                    setGpio3Fnc(1)
                    pins.setup(pio.P0_13, 1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    pins.setup(pio.P0_13, 0)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 3 then -- 橙灯闪烁一秒
                    pins.close(pio.P0_13)
                    setGpio3Fnc(1)
                    pio.pin.pwm(13, 200, 600, -1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    pio.pin.pwm(13, 0, 0, -1)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 4 then -- 红灯闪烁一秒
                    setGpio3Fnc(1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    sys.wait(1000 / (2 * countFlash))
                end
            end
        elseif lampDowns % 2 == 1 then
            if lampBreak then
                lampDowns = 0
                lampBreak = false
                break
            end
            sys.wait(1000)
        end
        if lampBreak then
            lampDowns = 0
            lampBreak = false
            break
        end
        lampDowns = lampDowns - 1
    end
    DoLampTask = true
end

-- 发送433信号
local function send433SignalTask(countSignalDownS)
    local afterSecondCount = afterSecond
    doSignalTask = false
    setGpio9Fnc(0)
    signalDowns = countSignalDownS
    send433RFSignal.InterruptSendMsg = true
    send433RFSignal.sendMsgTask()
    if not send433RFSignal.TimeId then
        send433RFSignal.signalRF433SerialCommunication(signalDowns,
            quake_intensity, "1",
            alarm433Bool)
    end
    sys.wait(1000)
    signalDowns = signalDowns - 1
    while signalDowns > 0 do
        if signalDowns == 1 and afterSecondCount == 0 then
            alarm433Bool = true
        end
        if not send433RFSignal.TimeId then
            send433RFSignal.signalRF433SerialCommunication(signalDowns,
                quake_intensity, "1",
                alarm433Bool)
        end
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        sys.wait(1000)
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        signalDowns = signalDowns - 1
    end
    if afterSecondCount > 0 then
        sys.taskInit(alarmLampOperationTask, afterSecondCount)
    end
    while afterSecondCount > 0 do
        log.info("afterSecondCount:", afterSecondCount)
        if afterSecondCount == 1 then alarm433Bool = true end
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        if not send433RFSignal.TimeId then
            log.info("继续响声音！！！")
            send433RFSignal.signalRF433SerialCommunication(1, quake_intensity,
                "0", alarm433Bool)
        end
        sys.wait(1000)
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        afterSecondCount = afterSecondCount - 1
    end
    setGpio9Fnc(1) -- 报警结束设置静音
    doSignalTask = true
    alarm433Bool = false
    sys.wait(5000)
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(0)
        log.info("音量为75，结束")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(0)
        log.info("音量为50，结束")
    elseif alertVolume <= 25 and alertVolume > 0 then
        setGpio17Fnc(0)
        log.info("音量为25，结束")
    end -- 音量测试恢复正常（大音量）
end

-- 声音报警
local function alarmVoiceTask(countToneDownS)
    local waitCout = afterSecond
    doToneTask = false
    setGpio9Fnc(0)
    setGpio10Fnc(1)
    toneDowns = countToneDownS
    if string.len(exerciseText) > 0 then
        ttsStr = exerciseText
    elseif string.len(exerciseText) == 0 then
        ttsStr = "地震预警演练，地震预警演练"
    end
    audio.play(TTS, "TTS", ttsStr, 7)
    while toneDowns > 0 do
        log.info("setGpio1Fnc")
        if toneDowns <= 10 then
            log.info("tts voice")
            ttsStr = tostring(toneDowns)
            audio.play(TTS, "TTS", ttsStr, 5)
        end
        -- if math.fmod(countAlarmDrill, 12) == 0 then uartTask.write(0x0C) end
        if toneBreak then
            -- uartTask.write(0x0C)
            toneBreak = false
            toneDowns = 0
            break
        end
        sys.wait(1000)
        if toneBreak then
            -- uartTask.write(0x0C)
            toneBreak = false
            toneDowns = 0
            break
        end
        toneDowns = toneDowns - 1
        -- countAlarmDrill = countAlarmDrill + 1
    end
    log.info("waitCout0", waitCout)
    while waitCout > 0 do
        log.info("waitCout1", waitCout)
        sys.wait(1000)
        waitCout = waitCout - 1
    end
    setGpio9Fnc(1) -- 报警结束设置静音
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(0)
        log.info("音量为75，结束，alarm")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(0)
        log.info("音量为50，结束，alarm")
    elseif alertVolume <= 25 and alertVolume > 0 then
        setGpio17Fnc(0)
        log.info("音量为25，结束，alarm")
    end -- 音量测试恢复正常（大音量）
    setGpio10Fnc(0)
    doToneTask = true
end

-- 地震预警系统
-- 两个功能：1.预警系统演练（tts语音播报3遍同时报警音触发）
-- 入参：mqttData接收的预警信息
function EarthquakeWarningDrillSystem(tjsondata)
    local msgCode, tClock, sysTime, eqlogInfo, errInfo = nil, os.date("*t"), "",
        "", ""
    sysTime = earthquakeWaring.GetSystemTime()
    if "false" == enable433 then
        enable433 = false
    elseif "true" == enable433 then
        enable433 = true
    end
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(1)
        log.info("音量为75")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(1)
        log.info("音量为50")
    elseif alertVolume <= 25 and alertVolume > 0 then
        setGpio17Fnc(1)
        log.info("音量为25")
    end
    if not tjsondata["1"] then
        countDownSDrill = 0
    else
        countDownSDrill = tonumber(tjsondata["1"])
    end
    if not tjsondata["2"] then
        quake_intensity = 0
    else
        quake_intensity = tonumber(tjsondata["2"])
    end
    if tjsondata["16"] then msgCode = tjsondata["16"] end
    log.info("tacountDownSDrillg", countDownSDrill, "quake_intensity",
        quake_intensity, "msgCode", msgCode)
    if msgCode == "0199" or quake_intensity == 0 then
        sysTime = earthquakeWaring.GetSystemTime()
        eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
            "预警演习取消！级\n"
        audio.stop()
        audio.play(TTS, "TTS",
            "预警系统演练取消。预警系统演练取消。预警系统演练取消",
            7)
        sys.wait(6400)
        if toneDowns > 0 then toneBreak = true end
        if lampDowns > 0 then lampBreak = true end
        if not doEmergencyLightOpen then
            emergencyLightOpenBreak = true
        end
        if signalDowns > 0 then signalBreak = true end
        while not doSignalTask do sys.wait(800) end
        if not send433RFSignal.TimeId then
            send433RFSignal.InterruptSendMsg = false
            send433RFSignal.sendMsgTask()
        end
    else
        sysTime = earthquakeWaring.GetSystemTime()
        eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
            "[预警演习:]到达秒数:" .. countDownSDrill ..
            "s,地震烈度:" .. quake_intensity .. "级\n"
        if toneDowns > 0 then toneBreak = true end
        if lampDowns > 0 then lampBreak = true end
        if not doEmergencyLightOpen then
            emergencyLightOpenBreak = true
        end
        if signalDowns > 0 then signalBreak = true end
        while not DoLampTask do sys.wait(800) end
        -- 报警灯任务
        log.info("alertLight", alertLight)
        if intensity2Threshold(quake_intensity) >= alertLight and DoLampTask then
            log.info("enter alertLight")
            sys.taskInit(alarmLampOperationTask, countDownSDrill)
        else
            sysTime = earthquakeWaring.GetSystemTime()
            eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                "[不满足报警灯临界值：]" ..
                "烈度转阈值：" ..
                tostring(intensity2Threshold(quake_intensity)) ..
                ",报警灯预设值：" .. tostring(alertLight) ..
                "[执行报警灯任务:]" .. tostring(not DoLampTask) ..
                "\n"
        end
        while not doSignalTask do sys.wait(800) end
        -- 433信号发送任务
        if intensity2Threshold(quake_intensity) >= alertSound and enable433 and
            doSignalTask then
            log.info("433send")
            sys.wait(200)
            sys.taskInit(send433SignalTask, countDownSDrill)
            sys.taskInit(emergencyLightOpenTask)
        else
            sysTime = earthquakeWaring.GetSystemTime()
            eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                "[阈值，发送433，执行发送433信号存在条件不满足]" ..
                "烈度转阈值：" ..
                tostring(intensity2Threshold(quake_intensity)) ..
                ",设定阈值：" .. alertSound ..
                ",是否发送433:" .. tostring(enable433) ..
                "执行发送433信号任务:" ..
                tostring(not doSignalTask) .. "\n"
        end
        log.info("alertSound", alertSound)
        while not doToneTask do sys.wait(800) end
        -- 报警音任务
        log.info("alertSound", alertSound)
        if intensity2Threshold(quake_intensity) >= countDown and doToneTask and
            quake_intensity >= configIntensity then
            log.info("alertSound enter")
            sys.wait(200)
            sys.taskInit(alarmVoiceTask, countDownSDrill)
            --[[ if doToneTask and quake_intensity >= configIntensity then
            log.info("alertSound enter")
            sys.wait(200)
            sys.taskInit(alarmVoiceTask, countDownSDrill) ]]
        else
            sysTime = earthquakeWaring.GetSystemTime()
            eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                "[不满足报警音临界值：]" ..
                "烈度阈值：" ..
                tostring(intensity2Threshold(quake_intensity)) ..
                ",报警音预设值：" .. countDown ..
                ",[执行报警音任务:]" .. tostring(not doToneTask) ..
                "\n"
        end
    end
    if eqlogInfo ~= "" and eqlogInfo ~= false then
        log.info("生成eq日志")
        logGenerator.generateLogTask(eqlogInfo, "log")
    end
    if errInfo ~= "" and errInfo ~= false then
        log.info("生成错误日志", errInfo)
        logGenerator.generateLogTask(errInfo, "log")
    end
end
